/*
 Автор: Швейкин Евгений Юрьевич

 Функциональное описание:
    Имитатор матрицы. 
    На выходе выдает не аналоговый сигнал, а цифровой. 
    Для простоты реализации с модуля управления матрицей заведены номера строк и столбцов.
    По сигналу exp_ena, начинает накапливаться значение фона, а по сигналу vhdata значение 
защелкивается. Т.е. vhdata это сигнал указывающий на захват/перенос заряда ячеек (пока это сигнал
подключения фотоячеек матрицы к нагрузке).
    Можно подать знаение элементов с внешнего блока. Для этого подается значение data_i и 
устанавливается сигнал init_mem_data_ena.
    В качестве источника внешних данных может быть подключена память, в этом случае для адресации 
использоваться должны номера строк и столбцов.
    Если используется фифо, то он должен находиться в режиме ASK (запрос нового слова). Для запроса
служит однотактовый сигнал init_mem_data_rdreq.
*/
`timescale 1ns / 10ps
//    ********************** НАЧАЛО МОДУЛЯ *********************************************************
module mod_matrix_im
    #(  parameter freq_p        = 100_000_000,
        parameter col_p         = 320,
        parameter row_p         = 240
    )
    (   input  logic            reset_n,
        input  logic            clk,

        input  logic            vldata_i,
        input  logic            vhdata_i,
        input  logic            vrdata_i,
        input  logic            vclamp_i,
        
        input  logic            vlsync_i,   // Синхроимпульсы
        input  logic            vrsync_i,
        input  logic            vhsync_i,
        
        input  logic [15:0]     init_mem_data,
        input  logic            init_mem_data_ena,
        output logic [31:0]     init_mem_data_addr,

        output logic [15:0]     matrix_data_o,
        output logic            matrix_data_wre_o,

        output logic [9:0]      col,
        output logic [9:0]      row
        
    );

//    ********************* КОНСТАНТЫ **************************************************************
    localparam int     adc_width_lp             = 14;
    localparam longint max_exp_length_us_lp     = 54;
    localparam longint max_exp_cnt_lp           = max_exp_length_us_lp * freq_p / 1_000_000;
    localparam longint brigh_coef_lp            = (2**adc_width_lp) / max_exp_cnt_lp;
    
//    ********************* СОЗДАНИЕ И ОПИСАНИЕ ПЕРЕМЕННЫХ *****************************************
    
    logic [15:0]    background_cnt;
    logic [15:0]    background_latch;
    logic [15:0]    data;
    
    logic           vhsync_0;
    logic           vhsync_1;
    logic           vhsync_fall;
    logic           vhsync_rise;

    logic           vhdata_0;
    logic           vhdata_1;
    logic           vhdata_rise;   

    logic           vclamp_0;
    logic           vclamp_1;
    logic           vclamp_fall;
    logic           vclamp_rise;  
    
    logic           vldata;     // Управление левым вертикальным регистром
                                // 1 - заряд ячеек до 1, 0 - разряд фототоком
                                // Определяет время экспозиции
    logic           vrdata;     // Управление правым вертикальным регистром
                                // Сброс фотоячеек

    logic           vhdata;     // Подключим к нагрузке

//  ********************* БЛОК НЕПРЕРЫВНЫХ НАЗНАЧЕНИЙ ASSIGN ***************************************


//  ********************* ОПИСАНИЕ ПРОЦЕССОВ *******************************************************
    always_ff @(posedge clk)
    begin
        if (vlsync_i)
            vldata  <= vldata_i;
        else;
        
        if (vrsync_i)
            vrdata  <= vrdata_i;
        else;
        
        vhdata  <= vhdata_i;
    end

    always_ff @(posedge clk)
    begin
        if (vhdata)
            col <= 10'd0;
        else if (vhsync_fall)
            col <= col + 10'd1;
        else;
        
        if (vrdata)
            row <= -10'd1;
        else if (vhdata_rise)
            row <= row + 10'd1;
        else;
    end

    always_ff @(posedge clk)
    begin
        vhsync_0     <= vhsync_i;
        vhsync_1     <= vhsync_0;
        vhsync_fall  <= vhsync_1 & (~vhsync_0);
        vhsync_rise  <= vhsync_0 & (~vhsync_1);
        
        vhdata_0     <= vhdata;
        vhdata_1     <= vhdata_0;
        vhdata_rise  <= vhdata_0 & (~vhdata_1);
        
        vclamp_0     <= vclamp_i;
        vclamp_1     <= vclamp_0;
        vclamp_fall  <= vclamp_1 & (~vclamp_0);
    end

    always_ff @(posedge clk)
    begin
        if (vldata)
            background_cnt  <= 2**adc_width_lp - 1;
        else if (background_cnt > brigh_coef_lp)
            background_cnt  <= background_cnt - brigh_coef_lp;
        else
            background_cnt  <= 16'd0;
        
        if (vhdata_rise)
            background_latch    <= background_cnt;
        else;
    end
    
    always_ff @(posedge clk)
    begin
        init_mem_data_addr <= col + row * col_p;
        if(vhsync_rise) begin
            if (init_mem_data_ena)
                data[15:0]  <= init_mem_data;
            else begin
                // Кубики с увеличивающейся яркостью, размером 4*4 + фон зависящий от экспозиции.
                //data  <= background_latch + {4'd0, col[9:2], 2'd0} + {4'd0, row[9:2], 2'd0};
                data    <= {8'd0, row[7:4], 4'd0};  //{8'd0, col[7:4], 4'd0} + 
            end
        end
        else;
    end

    always_ff @(posedge clk)
    begin
        matrix_data_wre_o  <= vclamp_fall;
//        if (vclamp_i) begin
//            matrix_data_o  <= 2**adc_width_lp - 1;
//        end
//        else begin
            if (data <= 2**adc_width_lp - 1)
                matrix_data_o <= data;
            else
                matrix_data_o <= 2**adc_width_lp - 1;
      //  end
    end
    
    
endmodule